package org.lyfeng.spring.beans.factory.support;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.lyfeng.spring.aop.AbstractAspectRegister;
import org.lyfeng.spring.aop.support.ProxyFactory;
import org.lyfeng.spring.aop.support.ProxyType;
import org.lyfeng.spring.beans.factory.config.SingletonBeanRegistry;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

public class DefaultSingletonBeanRegistry  extends AbstractAspectRegister implements SingletonBeanRegistry{
	
	protected static final Object NULL_OBJECT = new Object();
	
	/**singleObjects与registerSingletons锁**/
	Lock singletonBeanLock=new ReentrantLock();
	/**dependentBeanMap锁**/
	Lock dependentBeanLock=new ReentrantLock();
	
	/**bean实例的保存数据结构:bean name --> bean instance**/
	protected final Map<String,Object> singletonObjectsMap=new ConcurrentHashMap<String, Object>(64);
	
	/**bean实例的依赖set**/
	protected final Map<String,Set<String>> dependentBeanMap=new ConcurrentHashMap<String,Set<String>>(64);
	
	/**candidate for inject**/
	private final Map<String,Set<String>> candidateInjectBeanMap=new ConcurrentHashMap<String,Set<String>>(32);
	
	/**注册的bean**/
	protected final Set<String> registeredSingletons = new LinkedHashSet<String>(64);
	
	@Override
	public void registerSingleton(String beanName, Object singletonObject) {
		Assert.notNull(beanName, "'beanName'不能为空");
		singletonBeanLock.lock();
		try{
			boolean ifConftained=this.singletonObjectsMap.containsKey(beanName);
			if(ifConftained)
			{
				throw new IllegalStateException(String.format("注册bean[%s]失败,重复注册",beanName));
			}
			addSingleton(beanName, singletonObject);
		}finally{
			singletonBeanLock.unlock();
		}
	}
	
	protected void addSingleton(String beanName,Object singleObject)
	{
		singletonBeanLock.lock();
		try{
			this.singletonObjectsMap.put(beanName, null==singleObject?NULL_OBJECT:singleObject);
			this.registeredSingletons.add(beanName);
		}finally{
			singletonBeanLock.unlock();
		}
	}
	
	@Override
	public Object getSingleton(String beanName) {
		return this.singletonObjectsMap.get(beanName);
	}

	@Override
	public boolean containsSingleton(String beanName) {
		return this.singletonObjectsMap.containsKey(beanName);
	}

	@Override
	public String[] getSingletonNames() {
		singletonBeanLock.lock();
		try{
			return StringUtils.toStringArray(this.registeredSingletons);
		}finally{
			singletonBeanLock.unlock();
		}
	}

	@Override
	public int getSingletonCount() {
		singletonBeanLock.lock();
		try{
			return this.registeredSingletons.size();
		}finally{
			singletonBeanLock.unlock();
		}
	}

	@Override
	public void registerDependentBean(String beanName, String dependentName) {
		dependentBeanLock.lock();
		try{
			Set<String> dependentBeans=this.dependentBeanMap.get(beanName);
			if(null==dependentBeans)
			{
				dependentBeans=new LinkedHashSet<String>(8);
				this.dependentBeanMap.put(beanName, dependentBeans);
				this.candidateInjectBeanMap.put(beanName, dependentBeans);
			}
			dependentBeans.add(dependentName);
		}finally{
			dependentBeanLock.unlock();
		}
	}
	/**
	 * 递归销毁bean，对依赖的bean需要做是否有其他bean依
	 * 赖的判断处理？？？？？？？？？？？？？
	 */
	@Override
	public void destroyBean(String beanName) {
		if(singletonBeanLock.tryLock()&&dependentBeanLock.tryLock())
		{
			try{
				this.singletonObjectsMap.remove(beanName);
				Set<String> deptBeans=this.dependentBeanMap.remove(beanName);
				for(String s:deptBeans)
				{
					destroyBean(s);
				}
				this.registeredSingletons.remove(beanName);
			}finally{
				singletonBeanLock.unlock();
				dependentBeanLock.unlock();
			}
		}
	}

	@Override
	public void resolveAspect() {
		Iterator<Map.Entry<String, Object>> it = singletonObjectsMap.entrySet().iterator();
		while(it.hasNext())
		{
			Map.Entry<String, Object> entry=it.next();
			String key=entry.getKey();
			Object target=entry.getValue();
			Object proxyObj=ProxyFactory.createProxy(target, super.getAopBeanAsList(), ProxyType.JDK);
			singletonObjectsMap.put(key, proxyObj);
		}
	}

}
